﻿using System;
using System.Net;

using Tulde.Windows.Music.Mp3Tunes;
using System.Collections.Generic;
using Tulde.Windows.Music.ViewModel;

namespace Tulde.Windows.Music
{
    /// <summary>
    /// Using the MediaAPI provided by Mp3Tunes.com, retrieves data elements from a user's locker.  All data results are
    /// currently returned in JSON format.
    /// 
    /// To use this API, you must have a valid locker account with a partner token and username/password.
    /// 
    /// All network calls are implemented using a non blocking asynchronous model; therefore, when using WPF/Silverlight you do not need to  use the thread Dispatcher
    /// to reenter the UI thread.
    /// <example>
    /// Below is an example of DataBinding to a list in WPF.  We must first authenticate and get a valid session token.
    /// <![CDATA[
    ///  ICredentials credentials = new Mp3TunesCredentials
    ///        {
   ///             UserName = "user",
   ///             Password = "password",
   ///             Token = "partnerToken"
   ///         };
    ///  MusicServiceFactory.Instance.Authenticate(credentials, token =>
    ///        {
    ///            SecurityProvider.SetAuthenticationTokens(token);
    ///            MusicServiceFactory.Instance.EnumerateArtists(tracks =>
    ///            {
    ///                this.listArtists.DataContext = tracks.Artists;
    ///                Cursor = Cursors.Arrow;
    ///                this.mediaPlayer1.SetProgressBar(false);
    ///            });
    ///        });
    /// 
    /// ]]>
    /// </example>
    /// </summary>
    public class Mp3TunesMusicService : IMusicService
    {

        #region IMusicService Members
        /// <summary>
        /// Enumerates all artists existing in a locker.
        /// <example>
        /// <![CDATA[
        /// No need to call this.Dispatch because we are already executing on the UI Thread.
        /// instance.EnumerateArtists( result=> {
        ///      this.myDataBoundControl.DataContext = result.ArtistList;
        /// } );
        /// 
        /// ]]>
        /// 
        /// </example>
        /// </summary>
        /// <param name="callback">Callback databinding lambda</param>
        public void EnumerateArtists(Action<ArtistCollection> callback)
        {

            LockerDataService<ArtistCollection> dataService = new LockerDataService<ArtistCollection>();
            Uri uri = dataService.CreateServiceEndpoint(LockerDataOperations.lockerData,
                new DataServiceParameters
                {

                    ServiceType = ServiceTypes.artist
                }
               );
            dataService.InvokeAsynch<ArtistCollection>(uri, callback);

        }
        /// <summary>
        /// Enumerates all albums existing in a locker.
        /// <example>
        /// <![CDATA[
        /// No need to call this.Dispatch because we are already executing on the UI Thread.
        /// instance.EnumerateAlbums( result=> {
        ///      this.myDataBoundControl.DataContext = result.albumList;
        /// } );
        /// 
        /// ]]>
        /// 
        /// </example>
        /// </summary>
        /// <param name="callback">Callback databinding lambda</param>
        public void EnumerateAlbums(Action<AlbumCollection> callback)
        {
            LockerDataService<AlbumCollection> dataService = new LockerDataService<AlbumCollection>();
            Uri uri = dataService.CreateServiceEndpoint(LockerDataOperations.lockerData,
                new DataServiceParameters
                {

                    ServiceType = ServiceTypes.album
                }
               );
            dataService.InvokeAsynch<AlbumCollection>(uri, callback);
        }
        /// <summary>
        /// Enumerates all tracks existing in a locker.
        /// <example>
        /// <![CDATA[
        /// No need to call this.Dispatch because we are already executing on the UI Thread.
        /// instance.EnumerateTracks( result=> {
        ///      this.myDataBoundControl.DataContext = result.TrackList;
        /// } );
        /// 
        /// ]]>
        /// 
        /// </example>
        /// </summary>
        /// <param name="callback">Callback databinding lambda</param>
        public void EnumerateTracks(Action<TrackCollection> callback)
        {
            LockerDataService<TrackCollection> dataService = new LockerDataService<TrackCollection>();
            Uri uri = dataService.CreateServiceEndpoint(LockerDataOperations.lockerData,
                new DataServiceParameters
                {

                    ServiceType = ServiceTypes.track
                }
               );
            dataService.InvokeAsynch<TrackCollection>(uri, callback);
        }
        /// <summary>
        /// Enumerates all playlists existing in a locker.
        /// <example>
        /// <![CDATA[
        /// No need to call this.Dispatch because we are already executing on the UI Thread.
        /// instance.EnumeratePlaylists( result=> {
        ///      this.myDataBoundControl.DataContext = result.PlaylistList;
        /// } );
        /// 
        /// ]]>
        /// 
        /// </example>
        /// </summary>
        /// <param name="callback">Callback databinding lambda</param>
        public void EnumeratePlaylists(Action<PlaylistCollection> callback)
        {
            LockerDataService<PlaylistCollection> dataService = new LockerDataService<PlaylistCollection>();
            Uri uri = dataService.CreateServiceEndpoint(LockerDataOperations.lockerData,
                new DataServiceParameters
                {

                    ServiceType = ServiceTypes.playlist
                }
               );
            dataService.InvokeAsynch<PlaylistCollection>(uri, callback);
        }
        /// <summary>
        /// Search for artists given a search pattern.
        /// <example>
        /// <![CDATA[
        /// No need to call this.Dispatch because we are already executing on the UI Thread.
        /// instance.SearchArtists( "deer", result=> {
        ///      this.myDataBoundControl.DataContext = result.ArtistList;
        /// } );
        /// 
        /// ]]>
        /// 
        /// </example>
        /// </summary>
        /// <param name="pattern">Search Pattern</param>
        /// <param name="callback">Callback databinding lambda</param>
        public void SearchArtists(string pattern, Action<SearchResults> callback)
        {
           
            LockerSearchDataService<SearchResults> dataService = new LockerSearchDataService<SearchResults>();
            Uri uri = dataService.CreateServiceEndpoint(LockerDataOperations.lockerSearch,
                new DataServiceSearchParameters
                {

                    SearchPattern = pattern,
                    ServiceType = ServiceTypes.artist

                }
               );
            dataService.InvokeAsynch<SearchResults>(uri, callback);
        }
        /// <summary>
        /// Search for albums given a search pattern.
        /// <example>
        /// <![CDATA[
        /// No need to call this.Dispatch because we are already executing on the UI Thread.
        /// instance.SearchAlbums( "deer", result=> {
        ///      this.myDataBoundControl.DataContext = result.AlbumList;
        /// } );
        /// 
        /// ]]>
        /// 
        /// </example>
        /// </summary>
        /// <param name="pattern">Search Pattern</param>
        /// <param name="callback">Callback databinding lambda</param>
        public void SearchAlbums(string pattern, Action<SearchResults> callback)
        {
            LockerSearchDataService<SearchResults> dataService = new LockerSearchDataService<SearchResults>();
            Uri uri = dataService.CreateServiceEndpoint(LockerDataOperations.lockerSearch,
                new DataServiceSearchParameters
                {

                    SearchPattern = pattern,
                    ServiceType = ServiceTypes.album

                }
               );
            dataService.InvokeAsynch<SearchResults>(uri, callback);
        }
        /// <summary>
        /// Search for tracks given a search pattern
        /// <example>
        /// <![CDATA[
        /// No need to call this.Dispatch because we are already executing on the UI Thread.
        /// instance.SearchTracks( "deer", result=> {
        ///      this.myDataBoundControl.DataContext = result.TrackList;
        /// } );
        /// 
        /// ]]>
        /// 
        /// </example>
        /// </summary>
        /// <param name="pattern">Search Pattern</param>
        /// <param name="callback">Callback databinding lambda</param>
        public void SearchTracks(string pattern, Action<SearchResults> callback)
        {
            LockerSearchDataService<SearchResults> dataService = new LockerSearchDataService<SearchResults>();
            Uri uri = dataService.CreateServiceEndpoint(LockerDataOperations.lockerSearch,
                new DataServiceSearchParameters
                {

                    SearchPattern = pattern,
                    ServiceType = ServiceTypes.track

                }
               );
            dataService.InvokeAsynch<SearchResults>(uri, callback);
        }
        /// <summary>
        /// Returns a list of all albums for a given artist.
        /// </summary>
        /// <param name="artist">Artisit ViewModel Instance.  You really only need the ArtistId property</param>
        /// <param name="callback">Callback databinding lambda</param>
        public void GetArtistAlbums(ViewModel.Artist artist, Action<AlbumCollection> callback)
        {
            System.Net.WebClient client = new WebClient();
            LockerDataService<AlbumCollection> dataService = new LockerDataService<AlbumCollection>();
            Uri url = dataService.CreateServiceEndpoint(LockerDataOperations.lockerData, new DataServiceParameters
            {
                ServiceType = ServiceTypes.album,
                ArtistServiceKey = artist.ArtistId
            });

            dataService.InvokeAsynch<AlbumCollection>(url, callback);
        }
        /// <summary>
        /// Returns all tracks for a given album.
        /// </summary>
        /// <param name="album">The album  for which to find tracks.  Only really need albumId</param>
        /// <param name="callback">Callback databinding lambda</param>
        public void GetAlbumTracks(ViewModel.Album album, Action<TrackCollection> callback)
        {
            System.Net.WebClient client = new WebClient();
            LockerDataService<TrackCollection> dataService = new LockerDataService<TrackCollection>();
            Uri url = dataService.CreateServiceEndpoint(LockerDataOperations.lockerData, new DataServiceParameters
            {
                ServiceType = ServiceTypes.track,
                AlbumServiceKey = album.AlbumId
            });
            dataService.InvokeAsynch<TrackCollection>(url, callback);
        }


        /// <summary>
        /// Authenticate a user 
        /// </summary>
        /// <param name="credentials">An ICredentials instance</param>
        /// <param name="callback">Callback  lambda</param>
        public void Authenticate(ICredentials credentials, Action<ViewModel.AuthenticationToken> callback)
        {
            SecurityProvider.SetCredentials(credentials);
            AuthenticationService s = new AuthenticationService();
          
            Uri url = s.CreateServiceEndpoint(AuthenticationOperations.login, new AuthenticationServiceParameters
            {
                UserName = SecurityProvider.Credentials.UserName,
                Password = SecurityProvider.Credentials.Password
            });
            s.InvokeAsynch<AuthenticationToken>(url, callback);

        }
        /// <summary>
        /// Retrieves a playlist by playlistId.
        /// </summary>
        /// <param name="playlist">A playlist instance.  For predefined playlists such as shuffle, you pass a descendant of Playlist.  Currently the only
        /// implemented playlist descendant is ShufflePlaylist.</param>
        /// <param name="callback">Callback databinding lambda</param>
        public void GetPlaylist(Playlist playlist, Action<TrackCollection> callback)
        {
            
         
            LockerDataService<TrackCollection> dataService = new LockerDataService<TrackCollection>();
            Uri url = dataService.CreateServiceEndpoint(LockerDataOperations.lockerData, new DataServiceParameters
            {
                ServiceType = ServiceTypes.track,
                PlaylistServiceKey = playlist.PlaylistId
            });
            dataService.InvokeAsynch<TrackCollection>(url, callback);
        }

        #endregion


    }
}
